
package com.trydofor.id.mina;

import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;
import org.slf4j.Logger;

import com.trydofor.id.byta.Packet;
import com.trydofor.id.logs.Eventable;
import com.trydofor.id.logs.Eventer;
import com.trydofor.id.logs.LogLevel;

/**
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public class LoggingFilter extends IoFilterAdapter implements Eventable {
    
    /**
     * the events
     * 
     * @see org.apache.mina.core.filterchain.IoFilter
     */
    public enum Event implements Eventer.Event {
        /**
         * caught exception
         */
        EXCEPTION_CAUGHT,
        /**
         * received a message
         */
        MESSAGE_RECEIVED,
        /**
         * sent a message
         */
        MESSAGE_SENT,
        /**
         * created a session
         */
        SESSION_CREATED,
        /**
         * opened a session
         */
        SESSION_OPENED,
        /**
         * session idle
         */
        SESSION_IDLE,
        /**
         * closed a session
         */
        SESSION_CLOSED
    };
    
    private final Eventer eventer;
    
    /**
     * constructor.
     * 
     * @param eventer the eventer
     * @throws NullPointerException if eventer is null.
     */
    public LoggingFilter(Eventer eventer) {
        eventer.register(Event.EXCEPTION_CAUGHT, LogLevel.WARN);
        eventer.register(Event.MESSAGE_RECEIVED, LogLevel.INFO);
        eventer.register(Event.MESSAGE_SENT, LogLevel.INFO);
        eventer.register(Event.SESSION_CREATED, LogLevel.INFO);
        eventer.register(Event.SESSION_OPENED, LogLevel.INFO);
        eventer.register(Event.SESSION_IDLE, LogLevel.INFO);
        eventer.register(Event.SESSION_CLOSED, LogLevel.INFO);
        this.eventer = eventer;
    }
    
    /**
     * constructor.
     * 
     * @param logger the logger
     * @throws NullPointerException if logger is null.
     * @see #LoggingFilter(Eventer)
     */
    public LoggingFilter(Logger logger) {
        this(new Eventer(logger));
    }
    
    /**
     * {@inheritDoc}
     */
    public Eventer getEventer() {
        return eventer;
    }
    
    @Override
    public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception {
        eventer.log(Event.EXCEPTION_CAUGHT, cause, session.getRemoteAddress() + " got session exception");
        nextFilter.exceptionCaught(session, cause);
    }
    
    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
        String format = "received from {}, message={}";
        if (message instanceof Packet) {
            eventer.log(Event.MESSAGE_RECEIVED, format, session.getRemoteAddress(),
                    ((Packet) message).getHead());
        }
        else {
            eventer.log(Event.MESSAGE_RECEIVED, format, session.getRemoteAddress(), message);
        }
        
        nextFilter.messageReceived(session, message);
    }
    
    @Override
    public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest)
            throws Exception {
        Object message = writeRequest.getMessage();
        String format = "sent to {}, message={}";
        if (message instanceof Packet) {
            eventer.log(Event.MESSAGE_SENT, format, session.getRemoteAddress(), ((Packet) message).getHead());
        }
        else {
            eventer.log(Event.MESSAGE_SENT, format, session.getRemoteAddress(), message);
        }
        
        nextFilter.messageSent(session, writeRequest);
    }
    
    @Override
    public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
        eventer.log(Event.SESSION_CREATED, "created session of {}", session.getRemoteAddress());
        nextFilter.sessionCreated(session);
    }
    
    @Override
    public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
        eventer.log(Event.SESSION_OPENED, "opened session of {}", session.getRemoteAddress());
        nextFilter.sessionOpened(session);
    }
    
    @Override
    public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception {
        eventer.log(Event.SESSION_IDLE, "idle {} session of {}", status, session.getRemoteAddress());
        nextFilter.sessionIdle(session, status);
    }
    
    @Override
    public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
        eventer.log(Event.SESSION_CLOSED, "closed session of {}", session.getRemoteAddress());
        nextFilter.sessionClosed(session);
    }
}
